#ifndef padl_SYSTEM_CONTROL_BLOCK_
#define padl_SYSTEM_CONTROL_BLOCK_

#include "target.h"

/* System Control Block(SCB) modules include Memory Accelerator Module,
Phase Locked Loop, VPB divider, Power Control, External Interrupt,
Reset, and Code Security/Debugging */

#define padl_sysctrl_SYSCTRL		((padl_sysctrl_SysCtrlType *)0xE01FC000)

typedef struct
{
	/* Memory Accelerator Module (MAM) */
	REGISTER RW U32 MAMCR;
	REGISTER RW U32 MAMTIM;
	U32 RESERVED0[30];
	/* Phase Locked Loop (PLL) */
	union {
		REGISTER RW U32 PLLCON;
		struct {
			REGISTER RW BOOL enablePLL : 1;
			REGISTER RW BOOL connectPLL : 1;
		}PLLCON_detailed;
	};
	REGISTER RW U32 PLLCFG;
	union {
		REGISTER RO U32 PLLSTAT;
		struct {
			REGISTER RO U32		MSEL : 15;
			U32 RESERVED7 : 1;
			REGISTER RO U32 	NSEL : 8;
			REGISTER RO BOOL 	PLLE : 1;
			REGISTER RO BOOL 	PLLC : 1;
			REGISTER RO BOOL 	PLOCK : 1;
		}PLLSTAT_detailed;
	};
	REGISTER WO U32 PLLFEED;
	U32 RESERVED1[12];
	/* Power Control */
	REGISTER RW U32 PCON;
	REGISTER RW U32 PCONP;
	U32 RESERVED2[15];
	/* Clock Divider */
	REGISTER RW U32 CCLKCFG;
	REGISTER RW U32 USBCLKCFG;
	REGISTER RW U32 CLKSRCSEL;
	U32 RESERVED3[12];
	/* External Interrupts */
	REGISTER RW U32 EXTINT;
	REGISTER RW U32 INTWAKE;
	REGISTER RW U32 EXTMODE;
	REGISTER RW U32 EXTPOLAR;
	U32 RESERVED4[12];
	/* Reset, reset source identification */
	REGISTER RW U32 RSIR;
	/* RSID, code security protection */
	REGISTER RW U32 CSPR;
	/* AHB configuration */
	REGISTER RW U32 AHBCFG1;
	REGISTER RW U32 AHBCFG2;
	U32 RESERVED5[4];
	/* System Controls and Status */
	union {
		REGISTER RW U32 SCS;
		struct {
			REGISTER RW BOOL GPIOM : 1;
			U32 RESERVED8 : 4;
			REGISTER RW BOOL OSCEN : 1;
			REGISTER RO BOOL OSCSTAT : 1;
		}SCS_detailed;
	};
	U32 RESERVED6;
	/* Clock Divider */
	union {
		REGISTER RW U32 PCLKSEL0;
		struct {
			REGISTER RW U8 PCLK_WDT : 2;
			REGISTER RW U8 PCLK_TIMER0 : 2;
			REGISTER RW U8 PCLK_TIMER1 : 2;
			REGISTER RW U8 PCLK_UART0 : 2;
			REGISTER RW U8 PCLK_UART1 : 2;
			U32 : 2;
			REGISTER RW U8 PCLK_PWM1 : 2;
			REGISTER RW U8 PCLK_I2C0 : 2;
			REGISTER RW U8 PCLK_SPI : 2;
			REGISTER RW U8 PCLK_RTC : 2;
			REGISTER RW U8 PCLK_SSP1 : 2;
			REGISTER RW U8 PCLK_DAC : 2;
			REGISTER RW U8 PCLK_ADC : 2;
			REGISTER RW U8 PCLK_CAN1 : 2;
			REGISTER RW U8 PCLK_CAN2 : 2;
			REGISTER RW U8 PCLK_ACF : 2;
		}PCLKSEL0_detailed;
	};
	union {
		REGISTER RW U32 PCLKSEL1;
		struct {
			REGISTER RW U8 PCLK_BAT_RAM : 2;
			REGISTER RW U8 PCLK_GPIO : 2;
			REGISTER RW U8 PCLK_PCB : 2;
			REGISTER RW U8 PCLK_I2C1 : 2;
			U32 : 2;
			REGISTER RW U8 PCLK_SSP0 : 2;
			REGISTER RW U8 PCLK_TIMER2 : 2;
			REGISTER RW U8 PCLK_TIMER3 : 2;
			REGISTER RW U8 PCLK_UART2 : 2;
			REGISTER RW U8 PCLK_UART3 : 2;
			REGISTER RW U8 PCLK_I2C2 : 2;
			REGISTER RW U8 PCLK_I2S : 2;
			REGISTER RW U8 PCLK_MCI : 2;
			U32 : 2;
			REGISTER RW U8 PCLK_SYSCON : 2;
			U32 : 2;
		}PCLKSEL1_detailed;
	};
} padl_sysctrl_SysCtrlType;



#define PLL_SOURCE_INTERNAL_RC_OSC	0
#define PLL_SOURCE_MAIN_OSC			1
#define PLL_SOURCE_RTC_OSC			2

#define padl_sysctrl_PCLKSEL_CCLK_DIV_BY_4	0
#define padl_sysctrl_PCLKSEL_CCLK_DIV_BY_1	1
#define padl_sysctrl_PCLKSEL_CCLK_DIV_BY_2	2
#define padl_sysctrl_PCLKSEL_CCLK_DIV_BY_8	3


#define padl_sysctrl_ENABLE_MAIN_OSCILATOR() \
	(padl_sysctrl_SYSCTRL->SCS_detailed.OSCEN = TRUE)

#define padl_sysctrl_IS_MAIN_OSCILATOR_READY() \
	(padl_sysctrl_SYSCTRL->SCS_detailed.OSCSTAT)

#define padl_sysctrl_SET_PLL_CLOCK_SOURCE(source) \
	(padl_sysctrl_SYSCTRL->CLKSRCSEL = source)

#define padl_sysctrl_GET_PLL_CLOCK_SOURCE() \
	(padl_sysctrl_SYSCTRL->CLKSRCSEL)

#define padl_sysctrl_ENABLE_PLL() \
	padl_sysctrl_SYSCTRL->PLLCON_detailed.enablePLL = TRUE;\
	padl_sysctrl_SYSCTRL->PLLFEED = 0xAA;\
	padl_sysctrl_SYSCTRL->PLLFEED = 0x55;

#define padl_sysctrl_DISABLE_PLL() \
	padl_sysctrl_SYSCTRL->PLLCON_detailed.enablePLL = FALSE;\
	padl_sysctrl_SYSCTRL->PLLFEED = 0xAA;\
	padl_sysctrl_SYSCTRL->PLLFEED = 0x55;

#define padl_sysctrl_CONNECT_PLL() \
	padl_sysctrl_SYSCTRL->PLLCON_detailed.connectPLL = TRUE;\
	padl_sysctrl_SYSCTRL->PLLFEED = 0xAA;\
	padl_sysctrl_SYSCTRL->PLLFEED = 0x55;

#define padl_sysctrl_IS_PLL_CONNECTED() \
	(padl_sysctrl_SYSCTRL->PLLSTAT_detailed.PLLC)

#define padl_sysctrl_IS_PLL_LOCKED() \
	(padl_sysctrl_SYSCTRL->PLLSTAT_detailed.PLOCK)

#define padl_sysctrl_SET_PLL_CONFIGURATION(multiplier, divisor) \
	padl_sysctrl_SYSCTRL->PLLCFG = (multiplier & 0x7FFF) | ((divisor & 0xFF) << 16);\
	padl_sysctrl_SYSCTRL->PLLFEED = 0xAA;\
	padl_sysctrl_SYSCTRL->PLLFEED = 0x55;

#define padl_sysctrl_GET_ACTUAL_PLL_MUL() \
	(padl_sysctrl_SYSCTRL->PLLSTAT_detailed.MSEL)

#define padl_sysctrl_GET_ACTUAL_PLL_DIV() \
	(padl_sysctrl_SYSCTRL->PLLSTAT_detailed.NSEL)

#define padl_sysctrl_SET_CPU_CLOCK_DIVISOR(divisor) \
	(padl_sysctrl_SYSCTRL->CCLKCFG = divisor)

#define padl_sysctrl_GET_CPU_CLOCK_DIVISOR() \
	(padl_sysctrl_SYSCTRL->CCLKCFG)

#define padl_sysctrl_SET_USB_CLOCK_DIVISOR(divisor) \
	(padl_sysctrl_SYSCTRL->USBCLKCFG = divisor)

#define padl_sysctrl_ENABLE_FAST_GPIO() \
	(padl_sysctrl_SYSCTRL->SCS_detailed.GPIOM = TRUE)

#define padl_sysctrl_DISABLE_FAST_GPIO() \
	(padl_sysctrl_SYSCTRL->SCS_detailed.GPIOM = FALSE)

#define padl_sysctrl_SET_TIMER0_CLK(divider) \
	(padl_sysctrl_SYSCTRL->PCLKSEL0_detailed.PCLK_TIMER0 = divider)

#define padl_sysctrl_SET_TIMER1_CLK(divider) \
	(padl_sysctrl_SYSCTRL->PCLKSEL0_detailed.PCLK_TIMER1 = divider)

#define padl_sysctrl_SET_TIMER2_CLK(divider) \
	(padl_sysctrl_SYSCTRL->PCLKSEL1_detailed.PCLK_TIMER2 = divider)

#define padl_sysctrl_SET_TIMER3_CLK(divider) \
	(padl_sysctrl_SYSCTRL->PCLKSEL1_detailed.PCLK_TIMER3 = divider)


#define padl_sysctrl_GET_SYSTEM_FRQ() \
	((U32)((((padl_sysctrl_GET_PLL_CLOCK_SOURCE() == PLL_SOURCE_MAIN_OSC) ? (CRYSTAL_OSC_FRQ) :\
			(padl_sysctrl_GET_PLL_CLOCK_SOURCE() == PLL_SOURCE_RTC_OSC) ? (RTC_OSC_FRQ) :\
			(INTERNAL_RC_OSC_FRQ))\
		* ((padl_sysctrl_IS_PLL_CONNECTED())\
			? (2 * (padl_sysctrl_GET_ACTUAL_PLL_MUL() + 1) / (padl_sysctrl_GET_ACTUAL_PLL_DIV() + 1))\
			: (1)))\
		/ (padl_sysctrl_GET_CPU_CLOCK_DIVISOR() + 1)))



#endif /*padl_SYSTEM_CONTROL_BLOCK_*/
